<!-- 右键菜单 -->
<template>
	<div class="content-menu" @contextmenu.stop="contextmenuBox($event)">
		<slot />
		<Teleport to="body">
			<div class="menu" ref="menuRef" v-if="contextInfo.visible" :style="{ top: contextInfo.y + 'px', left: contextInfo.x + 'px' }">
				<ul>
					<template v-for="item in props.contentMenuOpt" :key="item.label">
						<li class="flex align-center justify-center" @click="item.handle(menuItem)" v-if="item.type != 'menu' ? true : isMenu">
							<lay-icon v-if="item.icon" :type="item.icon" class="margin-right"></lay-icon>{{ item.label }}
						</li>
					</template>
				</ul>
			</div>
		</Teleport>
	</div>
</template>

<script setup>
	import { ref, onUnmounted, onMounted, watch, nextTick } from "vue"

	const props = defineProps({
		contentMenuOpt: {
			label: Array,
			default: () => {
				return []
			}
		}
	})

	const x = ref(0)
	const y = ref(0)
	const visible = ref(false)
	const isMenu = ref(false) //点击的是否是菜单
	const menuItem = ref()	//右键菜单数据
	
	//监听左侧框架右键事件
	function contextmenuBox(e) {
		if(props.contentMenuOpt.length == 0) return
		e.preventDefault() // 阻止默认行为
		isMenu.value = false
		// 显示菜单
		visible.value = true
		// 获取鼠标位置
		x.value = e.clientX
		y.value = e.clientY
	}

	//监听菜单右键事件
	function useContextMenu(e, data) {
		e.preventDefault() // 阻止默认行为
		isMenu.value = data.id == 0 ? false : true
		menuItem.value = data
		// 显示菜单
		visible.value = true
		// 获取鼠标位置
		x.value = e.clientX
		y.value = e.clientY
	}

	// 关闭菜单
	const closeMenu = (e) => {
		visible.value = false
	}

	// 计算鼠标是否越界
	const isOut = (x, y, menu) => {
		const position = {
			x,
			y
		}

		if (x + menu.clientWidth > window.innerWidth) {
			position.x = window.innerWidth - (menu.clientWidth || 120)
		}
		if (y + menu.clientHeight > window.innerHeight) {
			position.y = window.innerHeight - (menu.clientHeight || 200)
		}
		return position
	}

	const menuRef = ref(null)

	const contextInfo = ref({
		x: 0,
		y: 0,
		visible: false
	})
	
	//计算右键菜单的位置
	function watchVisibleX() {
		contextInfo.value.visible = visible.value

		const elClientHeight = menuRef.value?.clientHeight
		const elClientWidth = menuRef.value?.clientWidth
		const position = isOut(x.value, y.value, {
			clientWidth: elClientWidth,
			clientHeight: elClientHeight
		})
		contextInfo.value.x = position.x
		contextInfo.value.y = position.y
	}

	onMounted(() => {
		window.addEventListener("click", closeMenu)
		window.addEventListener("contextmenu", closeMenu)

		// 监听显示隐藏
		watch(visible, () => {
			watchVisibleX()
		})
		// 监听位置变动
		watch(x, () => {
			watchVisibleX()
		})
	})

	onUnmounted(() => {
		// 移除事件
		window.removeEventListener("click", closeMenu)
		window.removeEventListener("contextmenu", closeMenu)
	})

	defineExpose({
		useContextMenu
	})
</script>

<style scoped lang="scss">
	.content-menu {
		width: 100%;
		min-height: calc(100% - 90px);
	}

	.menu {
		position: fixed;
		background-color: #fff;
		color: #000;
		border-radius: 8px;
		padding: 0;
		box-shadow: 0 1px 3px #ccc;
		border: 1px solid #ccc;
		transition: 0.3s ease;
		overflow: hidden;
		padding: 0 20px;
		z-index: 9999;

		ul {
			margin: 2px 0;
			padding: 0;
			list-style: none;
			flex-direction: column;
			align-items: center;

			li {
				height: 46px;
				width: 100%;
				line-height: 46px;
				text-align: center;
				border-bottom: 1px solid #efefef;
				cursor: pointer;
				transition: all 0.3s ease;

				&:hover {
					transform: translateY(-2px);
					color: #46bff0;
				}

				&:last-child {
					border-bottom: none;
				}
			}
		}
	}
</style>